home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / nr4.c < prev    next >
C/C++ Source or Header  |  1992-02-11  |  19KB  |  742 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "ax25.h"
  11. #include "lapb.h"
  12. #include "netrom.h"
  13. #include "nr4.h"
  14. #include <ctype.h>
  15.  
  16. #undef NR4DEBUG
  17.  
  18. /* Globals: */
  19.  
  20. /* The circuit table */
  21.  
  22. struct nr4circp Nr4circuits[NR4MAXCIRC] ;
  23.  
  24. /* Various limits */
  25.  
  26. unsigned Nr4window = 4 ;        /* Max window to negotiate */
  27. unsigned Nr4retries = 10 ;        /* Max retries */
  28. unsigned Nr4qlimit = 2048 ;        /* Max bytes on receive queue */
  29.  
  30. /* Timers */
  31.  
  32. long Nr4irtt = 15000 ;            /* Initial round trip time */
  33. long Nr4acktime = 3000 ;        /* ACK delay timer */
  34. long Nr4choketime = 180000 ;    /* CHOKEd state timeout */
  35.  
  36.  
  37. /* This function is called when a net/rom layer four frame */
  38. /* is discovered inside a datagram addressed to us */
  39.  
  40. void
  41. nr4input(hdr,bp)
  42. struct nr4hdr *hdr ;
  43. struct mbuf *bp ;
  44. {
  45.     struct nr4hdr rhdr ;
  46.     struct nr4cb *cb ;
  47.     struct ax25_addr dest ;
  48.     int op ;
  49.     unsigned window ;
  50.     int acceptc ;        /* indicates that connection should be accepted */
  51.     int newconn ;        /* indicates that this is a new incoming */
  52.                         /* connection.  You'll see. */
  53.     int gotchoke ;        /* The choke flag was set in this packet */        
  54.     
  55.     op = hdr->opcode & NR4OPCODE ;    /* Mask off flags */
  56.     
  57.     if (op == NR4OPCONRQ) {            /* process connect request first */
  58.         acceptc = 1 ;
  59.         newconn = 0 ;
  60.  
  61.         /* These fields are sent regardless of success */
  62.         
  63.         rhdr.yourindex = hdr->u.conreq.myindex ;
  64.         rhdr.yourid = hdr->u.conreq.myid ;
  65.         dest = hdr->u.conreq.node ;
  66.  
  67.         /* Check to see if we have already received a connect */
  68.         /* request for this circuit. */
  69.  
  70.         if ((cb = match_n4circ((int)hdr->u.conreq.myindex, (int)hdr->u.conreq.myid,
  71.                                   &hdr->u.conreq.user, &hdr->u.conreq.node))
  72.              == NULLNR4CB) {    /* No existing circuit if NULL */
  73.  
  74.             /* Try to get a new circuit */
  75.  
  76.             if ((cb = new_n4circ()) == NULLNR4CB) {
  77.                 acceptc = 0 ;
  78.             } else {
  79.             
  80.                 /* Window is set to min of the offered and local windows */
  81.                 
  82.                 window = hdr->u.conreq.window > Nr4window ?
  83.                          Nr4window : hdr->u.conreq.window ;
  84.  
  85.                 if (init_nr4window(cb, window) == -1) {
  86.                     free_n4circ(cb) ;
  87.                     acceptc = 0 ;
  88.                 } else {
  89.                     /* Set up control block */
  90.                     cb->yournum = hdr->u.conreq.myindex ;
  91.                     cb->yourid = hdr->u.conreq.myid ;
  92.                     cb->user = hdr->u.conreq.user ;
  93.                     cb->node = hdr->u.conreq.node ;
  94.                     cb->luser = mycall ;/* we are local user on incomings */
  95.                     cb->srtt = Nr4irtt ;/* Default round trip time */
  96.                     nr4defaults(cb) ;    /* set up timers, window pointers */
  97.                     cb->s_upcall = nr4_incom ;
  98.                     cb->state = NR4STDISC ;
  99.                     newconn = 1 ;
  100.                 } /* End if window successfully allocated */
  101.                 
  102.             }    /* End if new circuit available */
  103.             
  104.          } /* End if no existing circuit matching parameters */
  105.          
  106.         /* Now set up response */
  107.  
  108.         if (!acceptc) {
  109.             rhdr.opcode = NR4OPCONAK | NR4CHOKE ;/* choke means reject */
  110.             rhdr.u.conack.myindex = 0 ;
  111.             rhdr.u.conack.myid = 0 ;
  112.             rhdr.u.conack.window = 0 ;
  113.         } else {
  114.             rhdr.opcode = NR4OPCONAK ;
  115.             rhdr.u.conack.myindex = cb->mynum ;
  116.             rhdr.u.conack.myid = cb->myid ;
  117.             rhdr.u.conack.window = cb->window ;
  118.         }
  119.         nr4sframe(&dest, &rhdr, NULLBUF) ;
  120.  
  121.         /* Why, you ask, do we wait until now for the state change */
  122.         /* upcall?  Well, it's like this:  if the state change triggers */
  123.         /* something like the mailbox to send its banner, the banner */
  124.         /* would have gone out *before* the conn ack if we'd done this */
  125.         /* in the code above.  This is what happens when you don't plan */
  126.         /* too well.  Learn from my mistakes :-) */
  127.         
  128.         if (newconn)
  129.             nr4state(cb, NR4STCON) ;/* connected (no 3-way handshake) */
  130.             
  131.         free_p(bp) ;
  132.         return ;
  133.     } /* end connect request code */
  134.  
  135.     /* validate circuit number */
  136.  
  137.     if ((cb = get_n4circ((int)hdr->yourindex, (int)hdr->yourid)) == NULLNR4CB) {
  138.         free_p(bp) ;
  139.         return ;
  140.     }
  141.  
  142.     /* Check for choke flag */
  143.  
  144.     if (hdr->opcode & NR4CHOKE)
  145.         gotchoke = 1 ;
  146.     else
  147.         gotchoke = 0 ;
  148.     
  149.     /* Here's where the interesting stuff gets done */
  150.  
  151.     switch (cb->state) {
  152.       case NR4STCPEND:
  153.         switch (op) {
  154.           case NR4OPCONAK:
  155.             stop_timer(&cb->tcd) ;
  156.             if (gotchoke) {                    /* connect rejected */
  157.                 cb->dreason = NR4RREFUSED ;
  158.                 nr4state(cb, NR4STDISC) ;
  159.                 break ;
  160.             }
  161.             cb->yournum = hdr->u.conack.myindex ;
  162.             cb->yourid = hdr->u.conack.myid ;
  163.             window = hdr->u.conack.window > Nr4window ?
  164.                      Nr4window : hdr->u.conack.window ;
  165.  
  166.             if (init_nr4window(cb, window) == -1) {
  167.                 cb->dreason = NR4RRESET ;
  168.                 nr4state(cb, NR4STDISC) ;
  169.             } else {
  170.                 nr4defaults(cb) ;    /* set up timers, window pointers */
  171.                 
  172.                 if (cb->cdtries == 1)             /* No retries */
  173.                     cb->srtt = cb->tcd.count * MSPTICK ;/* Use measured rtt */
  174.                 else
  175.                     cb->srtt = Nr4irtt ;        /* else use default */
  176.                     
  177.                 nr4state(cb, NR4STCON) ;
  178.                 nr4output(cb) ;        /* start sending anything on the txq */
  179.             }
  180.             break ;
  181.  
  182.           default:        /* We can't respond to anything else without */
  183.                           /* Their ID and index */
  184.               free_p(bp) ;
  185.             return ;
  186.         }
  187.         break ;
  188.         
  189.       case NR4STCON:
  190.         switch (op) {
  191.           case NR4OPDISRQ:
  192.             /* format reply packet */
  193.             rhdr.opcode = NR4OPDISAK ;
  194.             rhdr.yourindex = cb->yournum ;
  195.             rhdr.yourid = cb->yourid ;
  196.     
  197.             nr4sframe(&cb->node, &rhdr, NULLBUF) ;
  198.  
  199.             cb->dreason = NR4RREMOTE ;
  200.             nr4state(cb, NR4STDISC) ;
  201.  
  202.             break ;
  203.             
  204.           case NR4OPINFO:
  205.             /* Do receive frame processing */
  206.               nr4rframe(cb, hdr->u.info.txseq, bp) ;
  207.  
  208.             /* Reset the choke flag if no longer choked.  Processing */
  209.             /* the ACK will kick things off again. */
  210.             
  211.             if (cb->choked && !gotchoke) {
  212.                 stop_timer(&cb->tchoke) ;
  213.                 cb->choked = 0 ;
  214.             }
  215.                 
  216.             /* We delay processing the receive sequence number until */
  217.             /* now, because the ACK might pull more off the txq and send */
  218.             /* it, and we want the implied ACK in those frames to be right */
  219.  
  220.             /* Only process NAKs if the choke flag is off.  It appears */
  221.             /* that NAKs should never be sent with choke on, by the way, */
  222.             /* but you never know, considering that there is no official */
  223.             /* standard for this protocol */
  224.             
  225.             if (hdr->opcode & NR4NAK && !gotchoke)
  226.                 nr4gotnak(cb, hdr->u.info.rxseq) ;
  227.  
  228.             /* We always do ACK processing, too, since the NAK of one */
  229.             /* packet may be the implied ACK of another.  The gotchoke */
  230.             /* flag is used to prevent sending any new frames, since */
  231.             /* we are just going to purge them next anyway if this is */
  232.             /* the first time we've seen the choke flag.  If we are */
  233.             /* already choked, this call will return immediately. */
  234.             
  235.             nr4ackours(cb, hdr->u.info.rxseq, gotchoke) ;
  236.  
  237.             /* If we haven't seen the choke flag before, purge the */
  238.             /* send window and set the timer and the flag. */
  239.             
  240.             if (!cb->choked && gotchoke)
  241.                 nr4choke(cb) ;
  242.             
  243.             break ;
  244.  
  245.           case NR4OPACK:
  246.             if (cb->choked && !gotchoke) {    /* clear choke if appropriate */
  247.                 stop_timer(&cb->tchoke) ;
  248.                 cb->choked = 0 ;
  249.             }
  250.                 
  251.               if (hdr->opcode & NR4NAK && !gotchoke)
  252.                 nr4gotnak(cb, hdr->u.ack.rxseq) ;    /* process NAKs */
  253.                 
  254.               nr4ackours(cb, hdr->u.ack.rxseq, gotchoke) ; /* and ACKs */
  255.  
  256.             if (!cb->choked && gotchoke)    /* First choke seen */
  257.                 nr4choke(cb) ;                /* Set choke status */
  258.  
  259.             break ;
  260.         }
  261.         break ;
  262.         
  263.       case NR4STDPEND:
  264.         switch (op) {
  265.           case NR4OPDISAK:
  266.               cb->dreason = NR4RNORMAL ;
  267.             nr4state(cb, NR4STDISC) ;
  268.             break ;
  269.             
  270.           case NR4OPINFO:
  271.             /* We can still do receive frame processing until */
  272.             /* the disconnect acknowledge arrives, but we won't */
  273.             /* bother to process ACKs, since we've flushed our */
  274.             /* transmit buffers and queue already. */
  275.             
  276.               nr4rframe(cb, hdr->u.info.txseq, bp) ;
  277.  
  278.             break ;
  279.         }
  280.     
  281.     }    /* End switch(state) */
  282.  
  283. }
  284.  
  285.  
  286. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  287.  * type is info.
  288.  */
  289.  
  290. void
  291. nr4sframe(dest, hdr, bp)
  292. struct ax25_addr *dest ;
  293. struct nr4hdr *hdr ;
  294. struct mbuf *bp ;
  295. {
  296.     void nr3output() ;
  297.     struct mbuf *n4b ;
  298.  
  299.     if ((n4b = htonnr4(hdr)) == NULLBUF) {
  300.         free_p(bp) ;
  301.         return ;
  302.     } else {
  303.         append(&n4b, bp) ;
  304.         nr3output(dest, n4b) ;
  305.     }
  306. }
  307.  
  308. /* Receive frame processing */
  309.  
  310. void
  311. nr4rframe(cb, rxseq, bp)
  312. stru